package com.xunwulian.cmpp.pdu;

import com.xunwulian.cmpp.Tools;
import com.xunwulian.cmpp.sms.ByteBuffer;
import com.xunwulian.cmpp.sms.NotEnoughDataInByteBufferException;
import com.xunwulian.cmpp.sms.PDUException;
import com.xunwulian.cmpp.sms.ShortMessage;
import com.xunwulian.cmpp.util.CmppConstant;
import org.codehaus.jackson.annotate.JsonIgnore;

import java.io.Serializable;

/**
 * @author lucien
 *         <p>
 *         TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style -
 *         Code Templates
 */
public class Submit extends Request implements Serializable {

    @JsonIgnore
    private static final long serialVersionUID = 9138270022148216469L;

    // 信息标识
    private byte[] msgId = new byte[8];

    // 相同Msg_Id的信息总条数，从1开始
    private byte pkTotal = 1;

    // 相同Msg_Id的信息序号，从1开始
    private byte pkNumber = 1;

    /**
     * 是否要求返回状态确认报告：
     * 0：不需要；
     * 1：需要。
     */
    private byte needReport = 1;

    // 信息级别
    private byte priority = 0;

    // 业务标识，是数字、字母和符号的组合
    private String serviceId = "";

    /**
     * 计费用户类型字段：
     * 0：对目的终端MSISDN计费；
     * 1：对源终端MSISDN计费；
     * 2：对SP计费；
     * 3：表示本字段无效，对谁计费参见Fee_terminal_Id字段。
     */
    private byte feeUserType = 0;

    /**
     * 被计费用户的号码，当Fee_UserType为3时该值有效，当Fee_UserType为0、1、2时该值无意义
     */
    private String feeTermId = "";

    /**
     * 被计费用户的号码类型，0：真实号码；1：伪码
     */
    private byte feeTermType = 0;

    /**
     * GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.9
     */
    private byte tpPid = 0;

    /**
     * GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.23,仅使用1位，右对齐
     */
    private byte tpUdhi = 0;

    /**
     * 信息格式：
     * 0：ASCII串；
     * 3：短信写卡操作；
     * 4：二进制信息；
     * 8：UCS2编码；
     * 15：含GB汉字。。。。。。
     */
    private String msgSrc = "";

    /**
     * 资费类别：
     * 01：对“计费用户号码”免费；
     * 02：对“计费用户号码”按条计信息费；
     * 03：对“计费用户号码”按包月收取信息费。
     */
    private String feeType = "01";

    /**
     * 资费代码（以分为单位）。
     * “00”：免费
     * “99”：包月
     * “98”：封顶
     * “01”--“10”：0.01元--0.10元
     * “11”--“50”：以0.05元递增
     * “51”--“80”：以0.10元递增
     * “81”--“97”：保留
     */
    private String feeCode = "05";

    /**
     * 存活有效期，格式遵循SMPP3.3协议
     */
    private String validTime = "";

    /**
     * 定时发送时间，格式遵循SMPP3.3协议
     */
    private String atTime = "";

    /**
     * 源号码。SP的服务代码或前缀为服务代码的长号码, 网关将该号码完整的填到SMPP协议Submit_SM消息相应的source_addr字段，
     * 该号码最终在用户手机上显示为短消息的主叫号码。
     */
    private String srcId = "";

    // 接收信息的用户数量(小于100个用户)
    private byte destTermIdCount = 0;

    // 接收短信的MSISDN号码
    private String destTermId[] = new String[0];

    /**
     * 接收短信的用户的号码类型，0：真实号码；1：伪码
     */
    private byte destTermIdType = 0;

    /**
     * 信息长度(Msg_Fmt值为0时 小于160个字节；其它小于等于140个字节)，取值大于或等于0。
     */
//  private byte Msg_Length = 0;

//  private String Msg_Content;

    private ShortMessage sm = new ShortMessage();

    /**
     * 点播业务使用的LinkID，非点播类业务的MT流程不使用该字段
     */
    private String linkId = "";

    public Submit() {
        super(CmppConstant.CMD_SUBMIT);
    }

    public Submit(String[] destTermId, int seqNumber, String content,
                  String serviceId,
                  String srcId,
                  String msgSrc) {

        super(CmppConstant.CMD_SUBMIT);

        header.setSequenceNumber(seqNumber);

        // Messege ID
        this.msgId = Tools.GetMsgid();

        // Service ID
        this.serviceId = serviceId;

        // 源号码
        this.srcId = srcId;

        // SP_ID
        this.msgSrc = msgSrc;

        this.destTermId = destTermId;

        this.destTermIdCount = (byte) destTermId.length;

        // 是否需要短信汇报
        this.needReport = (byte) 1;

        this.sm = new ShortMessage(content);
    }

    /**
     * 字节数组转换为SUBMIT对象
     *
     * @param buffer
     * @throws PDUException
     */
    public void setBody(ByteBuffer buffer)
            throws PDUException {
        try {
            msgId = buffer.removeBytes(8).getBuffer();
            pkTotal = buffer.removeByte();
            pkNumber = buffer.removeByte();
            needReport = buffer.removeByte();
            priority = buffer.removeByte();
            serviceId = buffer.removeStringEx(10);
            feeUserType = buffer.removeByte();
            feeTermId = buffer.removeStringEx(32);
            feeTermType = buffer.removeByte();
            tpPid = buffer.removeByte();
            tpUdhi = buffer.removeByte();
            byte msgFormat = buffer.removeByte();
            msgSrc = buffer.removeStringEx(6);
            feeType = buffer.removeStringEx(2);
            feeCode = buffer.removeStringEx(6);
            validTime = buffer.removeStringEx(17);
            atTime = buffer.removeStringEx(17);
            srcId = buffer.removeStringEx(21);
            destTermIdCount = buffer.removeByte();
            destTermId = new String[destTermIdCount];
            for (int i = 0; i < destTermIdCount; i++)
                destTermId[i] = buffer.removeStringEx(32);
            destTermIdType = buffer.removeByte();
            byte signbyte = buffer.removeByte();
            int msgLength = signbyte < 0 ? signbyte + 256 : signbyte;
            sm.setData(buffer.removeBuffer(msgLength));
            sm.setMsgFormat(msgFormat);
            linkId = buffer.removeStringEx(20);
        } catch (NotEnoughDataInByteBufferException e) {
            throw new PDUException(e);
        }
    }

    /**
     * SUBMIT对象转换为字节数组
     *
     * @return
     */
    public ByteBuffer getBody() {
        ByteBuffer buffer = new ByteBuffer();
        buffer.appendBytes(msgId, 8);
        buffer.appendByte(pkTotal);
        buffer.appendByte(pkNumber);
        buffer.appendByte(needReport);
        buffer.appendByte(priority);
        buffer.appendString(serviceId, 10);
        buffer.appendByte(feeUserType);
        buffer.appendString(feeTermId, 32);
        buffer.appendByte(feeTermType);
        buffer.appendByte(tpPid);
        buffer.appendByte(tpUdhi);
        buffer.appendByte(sm.getMsgFormat());
        buffer.appendString(msgSrc, 6);
        buffer.appendString(feeType, 2);
        buffer.appendString(feeCode, 6);
        buffer.appendString(validTime, 17);
        buffer.appendString(atTime, 17);
        buffer.appendString(srcId, 21);
        buffer.appendByte((byte) destTermId.length);
        for (int i = 0; i < destTermId.length; i++)
            buffer.appendString(destTermId[i], 32);
        buffer.appendByte(destTermIdType);
        buffer.appendByte((byte) sm.getLength());
        buffer.appendBuffer(sm.getData());
        buffer.appendString(linkId, 20);
        return buffer;
    }

    public void setData(ByteBuffer buffer) throws PDUException {
        header.setData(buffer);
        setBody(buffer);
    }

    public ByteBuffer getData() {
        ByteBuffer bodyBuf = getBody();
        header.setCommandLength(CmppConstant.PDU_HEADER_SIZE + bodyBuf.length());
        ByteBuffer buffer = header.getData();
        buffer.appendBuffer(bodyBuf);
        return buffer;
    }


    //    public int getRespStatus() {
    //        return respStatus;
    //    }
    //
    //    public void setRespStatus(int respStatus) {
    //        this.respStatus = respStatus;
    //    }

    public Response createResponse() {
        SubmitResp resp = new SubmitResp();
        resp.setSequenceNumber(getSequenceNumber());
        return resp;
    }

    public String getAtTime() {
        return atTime;
    }

    public void setAtTime(String atTime) {
        this.atTime = atTime;
    }

    public String[] getDestTermId() {
        return destTermId;
    }

    public void setDestTermId(String[] destTermId) {
        this.destTermId = destTermId;
    }

    public byte getDestTermIdCount() {
        return destTermIdCount;
    }

    public void setDestTermIdCount(byte destTermIdCount) {
        this.destTermIdCount = destTermIdCount;
    }

    public String getFeeCode() {
        return feeCode;
    }

    public void setFeeCode(String feeCode) {
        this.feeCode = feeCode;
    }

    public String getFeeTermId() {
        return feeTermId;
    }

    public void setFeeTermId(String feeTermId) {
        this.feeTermId = feeTermId;
    }

    public byte getFeeTermType() {
        return feeTermType;
    }

    public void setFeeTermType(byte feeTermType) {
        this.feeTermType = feeTermType;
    }

    public String getFeeType() {
        return feeType;
    }

    public void setFeeType(String feeType) {
        this.feeType = feeType;
    }

    public byte getFeeUserType() {
        return feeUserType;
    }

    public void setFeeUserType(byte feeUserType) {
        this.feeUserType = feeUserType;
    }

    public byte[] getMsgId() {
        return msgId;
    }

    public void setMsgId(byte[] msgId) {
        this.msgId = msgId;
    }

    public String getMsgSrc() {
        return msgSrc;
    }

    public void setMsgSrc(String msgSrc) {
        this.msgSrc = msgSrc;
    }

    public byte getNeedReport() {
        return needReport;
    }

    public void setNeedReport(byte needReport) {
        this.needReport = needReport;
    }

    public byte getPkNumber() {
        return pkNumber;
    }

    public void setPkNumber(byte pkNumber) {
        this.pkNumber = pkNumber;
    }

    public byte getPkTotal() {
        return pkTotal;
    }

    public void setPkTotal(byte pkTotal) {
        this.pkTotal = pkTotal;
    }

    public byte getPriority() {
        return priority;
    }

    public void setPriority(byte priority) {
        this.priority = priority;
    }

    public String getServiceId() {
        return serviceId;
    }

    public void setServiceId(String serviceId) {
        this.serviceId = serviceId;
    }

    public String getSrcId() {
        return srcId;
    }

    public void setSrcId(String srcId) {
        this.srcId = srcId;
    }

    public byte getTpPid() {
        return tpPid;
    }

    public void setTpPid(byte tpPid) {
        this.tpPid = tpPid;
    }

    public byte getTpUdhi() {
        return tpUdhi;
    }

    public void setTpUdhi(byte tpUdhi) {
        this.tpUdhi = tpUdhi;
    }

    public String getValidTime() {
        return validTime;
    }

    public void setValidTime(String validTime) {
        this.validTime = validTime;
    }

    public byte getDestTermIdType() {
        return destTermIdType;
    }

    public void setDestTermIdType(byte destTermIdType) {
        this.destTermIdType = destTermIdType;
    }

    public String getLinkId() {
        return linkId;
    }

    public void setLinkId(String linkId) {
        this.linkId = linkId;
    }

    public String getMsgContent() {
        return sm.getMessage();
    }

    public byte getMsgFormat() {
        return sm.getMsgFormat();
    }

    public byte getMsgLength() {
        return (byte) sm.getLength();
    }

    public void setSm(ShortMessage sm) {
        this.sm = sm;
    }

    public ShortMessage getSm() {
        return this.sm;
    }


    public String name() {
        return "CMPP Submit";
    }

}
